package cn.yto.print.plugins;

import cn.yto.print.enums.PluginRegistryEnum;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.Nullable;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.util.concurrent.ListenableFutureCallback;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketHttpHeaders;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.client.ConnectionManagerSupport;
import org.springframework.web.socket.client.WebSocketClient;
import org.springframework.web.socket.handler.LoggingWebSocketHandlerDecorator;


public class SocketConnectionManager extends ConnectionManagerSupport {

    private final WebSocketClient wsClient;
    private final WebSocketHandler handlerDelegate;
    private final WebSocketHttpHeaders httpHeaders = new WebSocketHttpHeaders();
    private final PluginRegistryEnum pluginEnum;
    @Nullable
    private WebSocketSession activeSession;

    public SocketConnectionManager(WebSocketClient client,
                                   WebSocketHandler handler,
                                   String uriTemplate,
                                   PluginRegistryEnum printScoketEnum,
                                   Object... uriVariables) {
        super(uriTemplate, uriVariables);
        this.wsClient = client;
        this.handlerDelegate = wrapHandler(handler);
        this.pluginEnum = printScoketEnum;
    }

    protected WebSocketHandler wrapHandler(WebSocketHandler originalHandler) {
        return new LoggingWebSocketHandlerDecorator(originalHandler);
    }

    /**
     * 建立 WebSocket 连接
     */
    @Override
    protected void openConnection() {
        if (logger.isInfoEnabled()) {
            logger.info("Connecting to " + pluginEnum.getCode() + " socket at " + getUri());
        }
        ListenableFuture<WebSocketSession> handshakeFuture =
                wsClient.doHandshake(handlerDelegate, httpHeaders, getUri());
        handshakeFuture.addCallback(new ListenableFutureCallback<WebSocketSession>() {
            @Override
            public void onSuccess(@Nullable WebSocketSession session) {
                activeSession = session;
                logger.info(StringUtils.capitalize(pluginEnum.getCode()) + " plugin successfully connected");
            }

            @Override
            public void onFailure(Throwable throwable) {
                logger.info(StringUtils.capitalize(pluginEnum.getCode()) + " plugin failed to connect", throwable);
            }
        });
    }

    /**
     * 关闭 WebSocket 连接
     */
    @Override
    protected void closeConnection() throws Exception {
        WebSocketSession tmpSession = this.activeSession;
        if (tmpSession != null) {
            tmpSession.close();
        }
    }

    @Override
    protected boolean isConnected() {
        WebSocketSession tmp = this.activeSession;
        return tmp != null && tmp.isOpen();
    }

}

